using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class ShadertoyRenderPassFeature : ScriptableRendererFeature
{
    class ShadertoyRenderPass : ScriptableRenderPass
    {
        private Material m_Material;
        private int shaderPropertyIFrame = Shader.PropertyToID("iFrame");
        CommandBuffer myCommandBuffer = new CommandBuffer();

        public ShadertoyRenderPass(string passName)
        {
            profilingSampler = new ProfilingSampler(passName);
        }

        public void SetupMembers(Material material)
        {
            m_Material = material;
        }

        // This method is called before executing the render pass.
        // It can be used to configure render targets and their clear state. Also to create temporary render target textures.
        // When empty this render pass will render to the active camera render target.
        // You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
        // The render pipeline will ensure target setup and clearing happens in a performant manner.
        public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
        {
            cmd.SetGlobalInteger(shaderPropertyIFrame, Time.frameCount);
        }

        // Here you can implement the rendering logic.
        // Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
        // https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
        // You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
        {
            using (new ProfilingScope(myCommandBuffer, profilingSampler))
            {
                myCommandBuffer.DrawProcedural(Matrix4x4.identity, m_Material, 0, MeshTopology.Triangles, 3, 1);
                context.ExecuteCommandBuffer(myCommandBuffer);
                myCommandBuffer.Clear();
            }
        }

        // Cleanup any allocated resources that were created during the execution of this render pass.
        public override void OnCameraCleanup(CommandBuffer cmd)
        {
        }
    }

    /// <summary>
    /// The material used to render the full screen pass (typically based on the Fullscreen Shader Graph target).
    /// </summary>
    public Material passMaterial;

    ShadertoyRenderPass m_ScriptablePass;

    /// <inheritdoc/>
    public override void Create()
    {
        m_ScriptablePass = new ShadertoyRenderPass(name);

        // Configures where the render pass should be injected.
        m_ScriptablePass.renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
    }

    // Here you can inject one or multiple render passes in the renderer.
    // This method is called when setting up the renderer once per-camera.
    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        if (renderingData.cameraData.cameraType == CameraType.Preview ||
            renderingData.cameraData.cameraType == CameraType.Reflection)
            return;

        if (passMaterial == null)
        {
            Debug.LogWarningFormat(
                "The render feature \"{0}\" will not execute - no material is assigned. Please make sure a material is assigned for this feature on the renderer asset.",
                name);
            return;
        }
        m_ScriptablePass.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
        m_ScriptablePass.ConfigureInput(ScriptableRenderPassInput.None);
        m_ScriptablePass.SetupMembers(passMaterial);
        renderer.EnqueuePass(m_ScriptablePass);
    }
}